2023/12/2310832字符
jQuery 源码分析
(function () {
function jQuery (selector) {
return new jQuery.prototype.init(selector);
}
// dom 选择
jQuery.prototype.init = function (selector) {
this.length = 0;
// 如果参数为空,返回自己,防止报错
if (selector == null) {
return this;
}
// 选择dom对象且包装成jQuery对象
// 判断参数是否为string,再进行判断
if (typeof selector == 'string' && selector.indexOf('.') != -1) { // class
var dom = document.getElementsByClassName(selector.slice(1));
}else if (typeof selector == 'string' && selector.indexOf('#') != -1) { // id
var dom = document.getElementById(selector.slice(1));
}else if (typeof selector == 'string' && selector.match(/^\b/)) { // div
var dom = document.getElementsByTagName(selector);
}
// 参数是否为Element,不是则看 dom.length 是否为空
if (selector instanceof Element || dom.length == undefined) {
// 使拿到的对象 = dom || 自己
this[0] = dom || selector;
this.length ++;
}else { // dom.length 不为0时,正常返回索引值
for (var i = 0; i < dom.length; i++) {
this[i] = dom[i];
this.length ++;
}
}
}
// css() 样式
jQuery.prototype.css = function (config) {
for (var i = 0; i < this.length; i++) {
for (var attr in config) {
this[i].style[attr] = config[attr];
}
}
// 链式调用
return this;
}
// get()
jQuery.prototype.get = function (num) {
if (num == null) {
return [].slice.call(this, 0); // 类数组转为数组
}else {
if (num >= 0) { // 参数为正时拿到索引值的那个
return this[num];
}else { // 参数为负数时从后面索取
// ['a', 'b', 'c']
// -3+3, -2+3, -1+3
return this[num + this.length];
}
}
// return num != null ? (num >= 0 ? this[num] : this[num + this.length]) : [].slice.call(this, 0);
}
jQuery.prototype.pushStack = function (dom) {
if (dom.constructor != jQuery) {
dom = jQuery(dom);
}
dom.prevObject = this;
return dom;
}
// eq()
jQuery.prototype.eq = function (num) {
var dom = num != null ? (num >= 0 ? this[num] : this[num + this.length]) : null;
return this.pushStack(dom);
}
// add()
jQuery.prototype.add = function (selector) {
var curObj = jQuery(selector);
var baseObj = this;
var newObj = jQuery();
for (var i = 0; i < curObj.length; i++) {
newObj[newObj.length++] = curObj[i];
}
for (var i = 0; i < baseObj.length; i++) {
newObj[newObj.length++] = baseObj[i];
}
//
this.pushStack(newObj);
return newObj;
}
jQuery.prototype.end = function () {
return this.prevObject;
}
// 实现on注册自定义事件功能,同时实现trigger触发自定义事件功能
jQuery.prototype.on = function (type, handle) {
addEventListener && addEventListener(type, handle);
for (var i = 0; i < this.length; i ++) {
if(!this[i].cacheEvent) {
this[i].cacheEvent = {};
}
if (!this[i].cacheEvent[type]) {
this[i].cacheEvent[type] = [handle];
}else {
this[i].cacheEvent[type].push(handle);
}
}
}
jQuery.prototype.trigger = function (type) {
// 传入参数从第二位开始截取
var params = arguments.length > 1 ? [].slice.call(arguments, 1) : [];
for (var i = 0; i < this.length; i++) {
if (this[i].cacheEvent[type]) {
this[i].cacheEvent[type].forEach(function (ele, index) {
ele.apply(self, params)
});
}
}
}
jQuery.prototype.myQueue = function () {
var queueObj = this;
var queueName = arguments[0] || 'fx';
var addFunc = arguments[1] || null;
var len = arguments.length;
// 获取队列
if (len == 1) {
return queueObj[0][queueName];
}
// queue dom {chain: } 添加队列 或 往已有队列中添加内容
queueObj[0][queueName] == undefined ? queueObj[0][queueName] = [addFunc] : queueObj[0][queueName].push(addFunc);
return this;
}
jQuery.prototype.myDequeue = function (type) {
var self = this;
var queueName = arguments[0] || 'fx';
var queueArr = this.myQueue(queueName);
var currFunc = queueArr.shift();
if (currFunc == undefined) {
return;
}
var next = function () {
self.myDequeue(queueName);
}
currFunc(next);
return this;
}
jQuery.prototype.myDelay = function (duration) {
var queueArr = this[0]['fx'];
queueArr.push(function (next) {
setTimeout(function () {
next();
}, duration);
});
return this;
}
jQuery.prototype.myAnimate = function (json, callback) {
var len = this.length;
var self = this;
// 最后添加到队列里的内容函数
var baseFunc = function (next) {
var times = 0;
for (var i = 0; i < len; i++) {
startMove(self[i], json, function () {
times++;
if (times == len) {
callback && callback();
next();
}
});
}
}
this.myQueue('fx', baseFunc);
if ( this.myQueue('fx').length == 1 ) {
this.myDequeue('fx');
}
function getStyle (obj, attr) {
if (obj.currentStyle) {
return obj.currentStyle[attr];
}else {
return window.getComputedStyle(obj,false)[attr];
}
}
function startMove (obj, json, callblack) {
clearInterval(obj.timer);
var iSpeed;
var iCur;
var name;
obj.timer = setInterval(function () {
var bStop = true;
for (var attr in json) {
if (attr === 'opacity') {
name = attr;
iCur = parseFloat(getStyle(obj, attr)) * 100;
}else {
iCur = parseInt(getStyle(obj, attr));
}
iSpeed = (json[attr] - iCur) / 7;
if (iSpeed > 0) {
iSpeed = Math.ceil(iSpeed);
}else {
iSpeed = Math.floor(iSpeed);
}
if (attr === 'opacity') {
obj.style.opacity = (iCur + iSpeed) / 100;
}else {
obj.style[attr] = iCur + iSpeed + 'px';
}
if (json[attr] - iCur !== 0) {
bStop = false;
}
}
if (bStop) {
clearInterval(obj.timer);
callblack();
}
}, 30);
}
return this;
}
jQuery.callbacks = function () {
// 'once' 'memory' 'once memory' null
var options = arguments[0] || ''; // 存储参数
var list = []; // 通过add 来加入的方法
var fireIndex = 0; // 记录当前要执行的函数的索引
var fired = false; // 记录是否有被fire过
var args = []; // 实际参数列表
var fire = function () {
for (; fireIndex < list.length; fireIndex++) {
list[fireIndex].apply(window, args);
}
if (options.indexOf('once') != -1) {
list = [];
fireIndex = 0;
}
}
return {
add: function (func) {
list.push(func);
if (options.indexOf('memory') != -1 && fired) {
fire();
}
return this;
},
fire: function () {
fireIndex = 0;
args = arguments;
fired = true;
fire();
}
}
}
jQuery.deferred = function () {
// callback
// 3个callback
// done resolve fail reject progress notify
var arr = [[jQuery.callbacks('once memory'), 'done', 'resolve'],
[jQuery.callbacks('once memory'), 'fail', 'reject'],
[jQuery.callbacks('memory'), 'progress', 'notify']];
var pendding = true;
var deferred = {};
for (var i = 0; i < arr.length; i++) {
// arr[0][1]
// 注册
// deferred['done'] = function () {}
// deferred['fail'] = function () {}
// deferred['progress'] = function () {}
deferred[ arr[i][1] ] = (function (index) {
return function (func) {
arr[index][0].add(func)
}
})(i);
// 触发
// deferred['resolve'] = function () {}
// deferred['reject'] = function () {}
// deferred['notify'] = function () {}
deferred[ arr[i][2] ] = (function (index) {
return function () {
var args = arguments;
if (pendding) {
arr[index][0].fire.apply(window, args);
arr[index][2] == 'resolve' || arr[index][2] == 'reject' ? pendding = false : '';
}
}
})(i);
}
return deferred;
}
// 将所有方法挂载到 init 上
jQuery.prototype.init.prototype = jQuery.prototype;
window.$ = window.jQuery = jQuery; // 将 jQuery 挂在全局上
})()